package public

import (
	"context"
	"errors"
	"fmt"
	"gitee.com/wanjimao/dongli-kit/pkg"
	"gitee.com/wanjimao/dongli-platform/tools"
	helper2 "gitee.com/wanjimao/dongli-platform/tools/helper"
	"gitee.com/wanjimao/dongli-util/dancetiktok"
	"gitee.com/wanjimao/dongli-util/dancetiktok/enums/dancetiktokenumsmymongo"
	dancetiktokenumsredis "gitee.com/wanjimao/dongli-util/dancetiktok/enums/dancetiktokenumsmyredis"
	"gitee.com/wanjimao/dongli-util/dancetiktok/funcs"
	"gitee.com/wanjimao/dongli-util/dancetiktok/model/dancetiktokmodelmysql"
	"gitee.com/wanjimao/dongli-util/helper"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"gorm.io/gorm"
	"math/rand"
	"strconv"
	"strings"
	"time"

	"gitee.com/wanjimao/dongli-kit/mq/common"
	"gitee.com/wanjimao/dongli-kit/mq/miface"
	"gitee.com/wanjimao/dongli-kit/orm/nerrors"
	"gitee.com/wanjimao/dongli-kit/utility"
	"go.uber.org/zap"
	"google.golang.org/protobuf/proto"

	pb "gitee.com/wanjimao/dongli-platform/api/gen/profile/api"
	"gitee.com/wanjimao/dongli-platform/services/profile/changes"
	errors2 "gitee.com/wanjimao/dongli-platform/services/profile/errors"
	"gitee.com/wanjimao/dongli-platform/services/profile/internal/db/redis"
	redis2 "github.com/redis/go-redis/v9"
)

func (s *Service) IsProfileExist(ctx context.Context, request *pb.IsProfileExistRequest) (*pb.IsProfileExistResponse, error) {
	if request.Uid == "" {
		if uid, ok := ctx.Value(utility.UIDContextKey).(string); !ok {
			s.logger.Error("get uid from context err")
			return nil, errors2.ErrNoMetaData
		} else {
			request.Uid = uid
		}
	}

	if _, err := s.db.LoadProfile(request.Uid); err != nil {
		if errors.Is(err, nerrors.ErrNotFound) {
			return &pb.IsProfileExistResponse{Exist: false}, nil
		}
		s.logger.Error("load profile err", zap.Error(err))
		return nil, errors2.ErrGeneralFailure
	}

	return &pb.IsProfileExistResponse{Exist: true}, nil
}

func (s *Service) GetProfile(ctx context.Context, request *pb.GetProfileRequest) (*pb.GetProfileResponse, error) {
	if request.Uid == "" {
		if uid, ok := ctx.Value(utility.UIDContextKey).(string); !ok {
			s.logger.Warn("get uid from context err")
			return nil, errors2.ErrNoMetaData
		} else {
			request.Uid = uid
		}
	}
	if profile, err := s.db.LoadProfile(request.Uid); err != nil {
		if errors.Is(err, nerrors.ErrNotFound) {
			return nil, errors2.ErrNotFound
		}
		s.logger.Warn("load profile err", zap.Error(err))
		return nil, errors2.ErrGeneralFailure
	} else {
		resp := &pb.GetProfileResponse{
			Profile: profile.ToProto(),
		}
		if status := redis.GetProfileStatus(s.redisCli, request.Uid); len(status) > 0 {
			resp.Profile.OnlineStatus = status[request.Uid]
		}
		return resp, nil
	}
}

func (s *Service) CreateProfile(ctx context.Context, request *pb.CreateProfileRequest) (*pb.CreateProfileResponse, error) {
	if uid, ok := ctx.Value(utility.UIDContextKey).(string); !ok {
		s.logger.Error("get uid from context err")
		return nil, errors2.ErrNoMetaData
	} else if name, err := s.checkName(request.GetProfile().Nickname); err != nil {
		s.logger.Error("check name err", zap.Error(err), zap.String("nickname", request.GetProfile().Nickname))
		return nil, errors2.ErrGeneralFailure
	} else {
		request.Profile.Nickname = name
		request.Profile.RegisterTime = time.Now().Unix()
		if profile, err := s.db.CreateProfile(uid, request.Profile); err != nil {
			s.logger.Error("create profile err", zap.Error(err))
			return nil, errors2.ErrGeneralFailure
		} else {
			if err := redis.UpdateBasicWithProfile(s.redisCli, uid, request.Profile); err != nil {
				s.logger.Error("set basic info err", zap.Error(err))
			}
			return &pb.CreateProfileResponse{
				Profile: profile.ToProto(),
			}, nil
		}
	}
}

func (s *Service) checkName(name string) (string, error) {
	if isExist, err := redis.IsNameExist(s.redisCli, name); err != nil {
		return "", err
	} else if isExist {
		if name, err = redis.RandomName(s.redisCli, name); err != nil {
			return "", err
		}
	}
	return name, redis.SaveName(s.redisCli, name)
}

func (s *Service) UpdateProfile(ctx context.Context, request *pb.UpdateProfileRequest) (*pb.UpdateProfileResponse, error) {
	uid, ok := ctx.Value(utility.UIDContextKey).(string)
	if !ok {
		s.logger.Error("get uid from context err")
		return nil, errors2.ErrNoMetaData
	}

	if request.Profile != nil {
		if updated, err := s.updateProfileInfo(uid, request.Profile); err != nil {
			s.logger.Error("update profile info err", zap.Error(err))
			return nil, err
		} else {
			return &pb.UpdateProfileResponse{Profile: updated}, nil
		}
	}
	if request.Basic != nil {
		if err := redis.SetBasicInfo(s.redisCli, uid, request.Basic); err != nil {
			s.logger.Error("set basic info err", zap.Error(err))
		}
	}

	return &pb.UpdateProfileResponse{}, nil
}

func (s *Service) updateProfileInfo(uid string, update *pb.Profile) (*pb.Profile, error) {
	profile, err := s.db.LoadProfile(uid)
	if err != nil {
		s.logger.Error("load profile err", zap.Error(err))
		return nil, errors2.ErrLoadFailure
	}

	//修改了昵称
	if newName := update.Nickname; newName != "" && newName != profile.Data.Nickname {
		if err = redis.ChangeName(s.redisCli, profile.Data.Nickname, newName); err != nil {
			s.logger.Error("UpdateProfile SaveName fail！ err:%v", zap.Error(err))
			return nil, errors2.ErrUpdateFailure
		}
	}
	if err = profile.Update(func() bool {
		return profile.UpdateData(update)
	}); err != nil {
		s.logger.Error("update profile err", zap.Error(err))
		return nil, errors2.ErrUpdateFailure
	} else if err := s.OnProfileUpdate(uid, profile.ToProto()); err != nil {
		s.logger.Error("trigger watch event fail！ err:%v", zap.Error(err))
		return nil, errors2.ErrGeneralFailure
	}
	return profile.ToProto(), nil
}

func (s *Service) GetProfileStatus(_ context.Context, request *pb.GetProfileStatusRequest) (*pb.GetProfileStatusResponse, error) {
	status := redis.GetProfileStatus(s.redisCli, request.Uid...)
	resp := &pb.GetProfileStatusResponse{
		Status: make(map[string]int32),
	}
	for k, v := range status {
		resp.Status[k] = v
	}
	return resp, nil
}

func (s *Service) WatchProfile(request *pb.WatchProfileRequest, server pb.ProfileService_WatchProfileServer) error {
	topic := changes.MakeProfileTopic(request.Uid)
	_, err := s.mq.Subscribe(server.Context(), topic, func(msg miface.Message, err error) common.ConsumptionCode {
		if err != nil {
			s.logger.Error("subscribe party topic failed", zap.Error(err))
			return common.ConsumeNackPersistentFailure
		}
		change := &pb.Profile{}
		if err := proto.Unmarshal(msg.Data(), change); err != nil {
			s.logger.Error("unmarshal message failed", zap.Error(err))
			return common.ConsumeNackPersistentFailure
		}

		if err := server.Send(&pb.WatchProfileResponse{
			Profile: change,
		}); err != nil {
			s.logger.Error("send message failed", zap.Error(err))
			return common.ConsumeNackPersistentFailure
		}
		return common.ConsumeAck
	})
	if err != nil {
		s.logger.Error("subscribe party topic failed", zap.Error(err))
		return errors2.ErrGeneralFailure
	}
	<-server.Context().Done()
	return nil
}

func (s *Service) OnProfileUpdate(uid string, change *pb.Profile) error {
	if err := redis.UpdateBasicWithProfile(s.redisCli, uid, change); err != nil {
		return err
	}
	if data, err := proto.Marshal(change); err != nil {
		return err
	} else if err := s.mq.Publish(changes.MakeProfileTopic(uid), miface.WithBytes(data)); err != nil {
		return err
	}
	return nil
}

func (s *Service) LoginAccount(ctx context.Context, request *pb.LoginAccountRequest) (*pb.LoginAccountResponse, error) {
	//判断判断用户是否村子啊是否存在
	s.logger.Error(fmt.Sprintf("开始连接"))
	s.logger.Error(fmt.Sprintf("开始连接"))
	logInfo := pkg.LogInfo{
		Method:     "LoginAccount",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	resp := pb.LoginAccountResponse{}
	resp.RoleList = make([]*pb.SimpleRoleStruct, 0)
	var account dancetiktokmodelmysql.DanceUserAccount
	tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceUserAccount{}).Where("account = ?", request.Account).First(&account)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询用户异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
		return &resp, errors2.ErrLoadFailure
	}
	//不存在的话先创建
	if account.Id == 0 {
		//创建账号
		account = dancetiktokmodelmysql.DanceUserAccount{
			Account:    request.Account,
			Token:      request.Token,
			Platform:   int8(request.Platform),
			Channel:    int8(request.Channel),
			SdkChannel: request.SdkChannel,
			PubMode:    request.PubMode,
			Device:     request.Device,
			Os:         request.Os,
			Imei:       request.Imei,
			ClientVer:  request.ClientVer,
			PtId:       request.PtId,
		}
		if create := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceUserAccount{}).Create(&account); nil != create.Error {
			s.logger.Error(fmt.Sprintf("查询用户异常 logInfo:%+v err:%+v", logInfo, tx.Error))
			resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
			return &resp, errors2.ErrLoadFailure
		}
		resp.Account = account.Account
		resp.AccountId = account.Id
		return &resp, nil
	}
	resp.Account = account.Account
	resp.AccountId = account.Id
	//查询角色
	var accountRoleList []dancetiktokmodelmysql.DanceUserAccountRole
	tx = s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceUserAccountRole{}).Where("account_id = ?", account.Id).Find(&accountRoleList)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询角色列表异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
		return &resp, errors2.ErrLoadFailure
	}
	for _, i2 := range accountRoleList {
		resp.RoleList = append(resp.RoleList, &pb.SimpleRoleStruct{
			Pid:    uint32(i2.Id),
			Name:   i2.Name,
			Sex:    uint32(i2.Sex),
			Skin:   i2.Skin,
			Face:   i2.Face,
			Head:   i2.Head,
			Coat:   i2.Coat,
			Bottom: i2.Bottom,
			Shoe:   i2.Shoe,
			Sign:   i2.Sign,
			Photo:  i2.Photo,
		})
	}
	return &resp, nil
}

func (s *Service) CreateRole(ctx context.Context, request *pb.CreateRoleRequest) (*pb.CreateRoleResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "CreateRole",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	//判断判断用户是否村子啊是否存在
	resp := pb.CreateRoleResponse{}
	resp.Role = &pb.SimpleRoleStruct{}

	var account dancetiktokmodelmysql.DanceUserAccount
	tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceUserAccount{}).Where("id = ?", request.UserId).First(&account)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		s.logger.Error(fmt.Sprintf("查询账号异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		return &resp, nil
	}
	resp.Account = account.Account
	resp.CreateTime = uint32(account.CreatedAt.Unix())
	resp.Channel = uint32(account.Channel)
	var accountRole dancetiktokmodelmysql.DanceUserAccountRole
	tx = s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceUserAccountRole{}).Where("account_id = ?", request.UserId).First(&accountRole)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询角色异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return &resp, nil
	}

	//出现空格
	if strings.Contains(request.Role.Name, " ") {
		s.logger.Error(fmt.Sprintf("角色不名字不能出现空格 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.CreateRoleRoleNameCannotContainSpaces
		return &resp, nil
	}

	if !helper2.CommonHelperObject.CheckSpecialChar(request.Role.Name) {
		s.logger.Error(fmt.Sprintf("角色名字出现特殊字符 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.CreateRoleIllegalCharacterInRoleName
		return &resp, nil
	}

	if len(strings.Split(request.Role.Name, "")) > 20 {
		s.logger.Error(fmt.Sprintf("角色名字过长 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.CreateRoleRoleNameIsTooLong
		return &resp, nil
	}

	var accountRole2 dancetiktokmodelmysql.DanceUserAccountRole
	tx = s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceUserAccountRole{}).Where("name = ?", request.Role.Name).First(&accountRole2)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询角色异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.CreateRoleRepeatRoleName
		return &resp, nil
	}
	if accountRole2.Id != 0 {

	}

	insertRoleNameRedis := func() {
		Key2 := funcs.NewRedisTools(s.set.EnvServer, dancetiktokenumsredis.PlatformDanceMobile).GetPoolAllUserNameOccupied()
		f, err := s.redisCli.ZAdd(context.Background(), Key2, redis2.Z{
			Score:  float64(time.Now().Unix()),
			Member: request.Role.Name,
		}).Result()
		if nil != err {
			s.logger.Error(fmt.Sprintf("插入昵称到redis中异常 logInfo:%+v err:%+v f:%+v", logInfo, tx.Error, f))
		}
	}

	if accountRole.Id == 0 {

		begin := s.mysqlDb.MysqlDanceDb.Begin()
		needInsert := make([]dancetiktokmodelmysql.DanceBag, 0)
		//创建账号角色
		accountRole = dancetiktokmodelmysql.DanceUserAccountRole{
			AccountId: request.UserId,
			Name:      request.Role.Name,
			Sex:       int8(request.Role.Sex),
			Skin:      request.Role.Skin,
			Face:      request.Role.Face,
			Head:      request.Role.Head,
			Coat:      request.Role.Coat,
			Bottom:    request.Role.Bottom,
			Shoe:      request.Role.Shoe,
			Sign:      request.Role.Sign,
			Photo:     request.Role.Photo,
		}
		if create := begin.Model(&dancetiktokmodelmysql.DanceUserAccountRole{}).Create(&accountRole); nil != create.Error {
			begin.Rollback()
			resp.ErrCode = dancetiktok.ErrorLoginDataException
			return &resp, errors2.ErrLoadFailure
		} else {

			for _, idTmp := range []uint32{request.Role.Face, request.Role.Head, request.Role.Coat, request.Role.Bottom, request.Role.Shoe} {
				//id, _ := strconv.ParseInt(idTmp.Items, 10, 64)
				if idTmp == 0 {
					continue
				}
				addElement := dancetiktokmodelmysql.DanceBag{
					No:         int64(idTmp),
					RoleId:     accountRole.Id,
					Number:     1,
					ExpireTime: 0,
					CreateId:   accountRole.Id,
					UpdateId:   accountRole.Id,
					CreatedAt:  time.Now(),
					UpdatedAt:  time.Now(),
					DeletedAt:  gorm.DeletedAt{},
				}
				needInsert = append(needInsert, addElement)
			}
			if create := begin.Model(&dancetiktokmodelmysql.DanceBag{}).Create(&needInsert); nil != create.Error {
				s.logger.Error(fmt.Sprintf("插入数据异常 logInfo:%+v err:%+v", logInfo, tx.Error))
				begin.Rollback()
				resp.ErrCode = dancetiktok.ErrorLoginDataException
				return &resp, errors2.ErrNotFound
			}
			//存进redis
			//Key2 := funcs.NewRedisTools(s.set.EnvServer, dancetiktokenumsredis.PlatformDanceMobile).GetDanceAccountRoleHashKey(string(accountRole.Id))
			//pipeline := s.redisCli.Pipeline()
			//pipeline.HSet(context.Background(), Key2, dancetiktokenumsredis.DanceUserAccountRoleEnumsId, accountRole.Id)
			//pipeline.HSet(context.Background(), Key2, dancetiktokenumsredis.DanceUserAccountRoleEnumsName, accountRole.Name)
			//pipeline.HSet(context.Background(), Key2, dancetiktokenumsredis.DanceUserAccountRoleEnumsSex, accountRole.Sex)
			//pipeline.HSet(context.Background(), Key2, dancetiktokenumsredis.DanceUserAccountRoleEnumsSkin, accountRole.Skin)
			//pipeline.HSet(context.Background(), Key2, dancetiktokenumsredis.DanceUserAccountRoleEnumsFace, accountRole.Face)
			//pipeline.HSet(context.Background(), Key2, dancetiktokenumsredis.DanceUserAccountRoleEnumsHead, accountRole.Head)
			//pipeline.HSet(context.Background(), Key2, dancetiktokenumsredis.DanceUserAccountRoleEnumsCoat, accountRole.Coat)
			//pipeline.HSet(context.Background(), Key2, dancetiktokenumsredis.DanceUserAccountRoleEnumsBottom, accountRole.Bottom)
			//pipeline.HSet(context.Background(), Key2, dancetiktokenumsredis.DanceUserAccountRoleEnumsShoe, accountRole.Shoe)
			//pipeline.HSet(context.Background(), Key2, dancetiktokenumsredis.DanceUserAccountRoleEnumsSign, accountRole.Sign)
			//pipeline.HSet(context.Background(), Key2, dancetiktokenumsredis.DanceUserAccountRoleEnumsPhoto, accountRole.Photo)
			//_, err := pipeline.Exec(context.Background())
			//if nil != err && err != redis2.Nil {
			//	s.logger.Error(fmt.Sprintf("保存角色信息到redis异常 logInfo:%+v err:%+v", logInfo, err))
			//	resp.ErrCode = dancetiktok.TheInputTextContainsIllegalCharacters
			//	return &resp, errors2.ErrLoadFailure
			//}
		}
		resp.Role = &pb.SimpleRoleStruct{
			Pid:    uint32(accountRole.Id),
			Name:   accountRole.Name,
			Sex:    uint32(accountRole.Sex),
			Skin:   accountRole.Skin,
			Face:   accountRole.Face,
			Head:   accountRole.Head,
			Coat:   accountRole.Coat,
			Bottom: accountRole.Bottom,
			Shoe:   accountRole.Shoe,
			Sign:   accountRole.Sign,
			Photo:  accountRole.Photo,
		}
		//存储名字到redis中
		insertRoleNameRedis()
		return &resp, nil
	}
	//查询角色
	tx = s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceUserAccountRole{}).Where("account_id = ?", account.Id).First(&accountRole)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询角色异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return &resp, errors2.ErrLoadFailure
	}
	resp.Role = &pb.SimpleRoleStruct{
		Pid:    uint32(accountRole.Id),
		Name:   accountRole.Name,
		Sex:    uint32(accountRole.Sex),
		Skin:   accountRole.Skin,
		Face:   accountRole.Face,
		Head:   accountRole.Head,
		Coat:   accountRole.Coat,
		Bottom: accountRole.Bottom,
		Shoe:   accountRole.Shoe,
		Sign:   accountRole.Sign,
		Photo:  accountRole.Photo,
	}
	//存储名字到redis中
	insertRoleNameRedis()
	return &resp, nil
}

func (s *Service) LoginRole(ctx context.Context, request *pb.LoginRoleRequest) (*pb.LoginRoleResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "LoginAccount",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	//判断判断用户是否村子啊是否存在
	resp := pb.LoginRoleResponse{}
	resp.Role = &pb.SimpleRoleStruct{}
	//用户
	var accountRole dancetiktokmodelmysql.DanceUserAccountRole
	tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceUserAccountRole{}).Where("id = ?", request.Pid).First(&accountRole)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询角色异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return &resp, errors2.ErrLoadFailure
	}
	if accountRole.Id == 0 || accountRole.AccountId == 0 {
		s.logger.Error(fmt.Sprintf("取出的数据异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return &resp, errors2.ErrNotFound
	}
	//用户账号
	var account dancetiktokmodelmysql.DanceUserAccount
	tx = s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceUserAccount{}).Where("id = ?", accountRole.AccountId).First(&account)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询账号异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		return &resp, errors2.ErrLoadFailure
	}
	resp.Pid = uint32(accountRole.Id)
	resp.Channel = uint32(account.Channel)
	resp.CreateTime = uint32(account.CreatedAt.Unix())
	resp.OpenDays = 0
	resp.IsGm = 0
	resp.RoleToken = account.Token
	resp.Role = &pb.SimpleRoleStruct{
		Pid:    uint32(accountRole.Id),
		Name:   accountRole.Name,
		Sex:    uint32(accountRole.Sex),
		Skin:   accountRole.Skin,
		Face:   accountRole.Face,
		Head:   accountRole.Head,
		Coat:   accountRole.Coat,
		Bottom: accountRole.Bottom,
		Shoe:   accountRole.Shoe,
		Sign:   accountRole.Sign,
		Photo:  accountRole.Photo,
	}
	return &resp, nil
}

func (s *Service) RandName(ctx context.Context, request *pb.RandNameRequest) (*pb.RandNameResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "RandName",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	fmt.Println(logInfo)
	//判断判断用户是否村子啊是否存在
	resp := pb.RandNameResponse{}
	getRandName := func() (string, error) {
		//Key1 := funcs.NewRedisTools(s.set.EnvServer, dancetiktokenumsredis.PlatformDanceMobile).GetPoolUserNameRandom()
		//生成一个随机数
		//randNumber := int64(10)
		//if s.set.EnvServer != "pro" {
		//	randNumber = int64(10)
		//}
		randNumber := rand.Intn(100)
		//result, err := s.redisCli.ZRange(context.Background(), Key1, randNumber, randNumber).Result()
		//if nil != err {
		//	return "", errors.New(fmt.Sprintf("从随机名字的池子中取数据异常 err:%+v", err))
		//}
		//if len(result) <= 0 {
		//	return "", errors.New(fmt.Sprintf("数据不足 err:%+v", err))
		//}
		randName := tools.GlobalRandNameSlice[randNumber]
		Key2 := funcs.NewRedisTools(s.set.EnvServer, dancetiktokenumsredis.PlatformDanceMobile).GetPoolAllUserNameOccupied()
		f, err := s.redisCli.ZScore(context.Background(), Key2, randName).Result()
		if nil != err && err != redis2.Nil {
			return "", errors.New(fmt.Sprintf("查询被占用的用户昵称失败 %+v", err))
		}
		//如果不为0说明已经被占用，那么就把脏数据删掉
		if f != 0 {
			//i, err := s.redisCli.ZRem(context.Background(), Key1, result[0]).Result()
			//s.logger.Info(fmt.Sprintf("删除昵称池子的数据 logInfo:%+v i:%+v err:%+v", logInfo, i, err))
			return "", nil
		} else {
			return randName, nil
		}
	}

	nameRes := ""
	//10次机会，如果一直重复，放弃请求
	for i := 0; i < 10; i++ {
		name, err := getRandName()
		if nil != err {
			resp.ErrCode = dancetiktok.ErrorLoginDataException
			return &resp, errors2.ErrLoadFailure
		}
		if name == "" {
			continue
		}
		nameRes = name
		break
	}
	if nameRes == "" {
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return &resp, errors2.ErrLoadFailure
	}
	resp.Randname = nameRes
	return &resp, nil
}

func (s *Service) ChannelVariedInfo(ctx context.Context, request *pb.ChannelVariedInfoRequest) (*pb.ChannelVariedInfoResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "ChannelVariedInfo",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	resp := pb.ChannelVariedInfoResponse{
		ErrCode: 0,
		List:    make([]*pb.ChannelVariedInfo, 0),
	}

	fmt.Println(logInfo)
	//****************************************数据处理
	type tmpBalloons struct {
		Id_      string `bson:"_id"`       // id
		ChanelId int64  `bson:"chanel_id"` // id
		Sex      int64  `bson:"sex"`       // id
		Count    int64  `bson:"count"`     // id
	}
	collectionBalloons := s.mongoDb.MongoDb.Database(fmt.Sprintf(dancetiktokenumsmymongo.DatabaseGame, s.set.EnvServer)).Collection(dancetiktokenumsmymongo.MongoDanceChannelRole)
	//条件
	match := bson.D{
		{
			"$match", bson.D{
				{"channel_pid", bson.D{
					{"$eq", request.MajorId},
				}},
			},
		},
	}
	group := bson.D{{
		"$group", bson.D{
			{"_id", bson.D{
				{"chanel_id", "$chanel_id"},
				{"sex", "$sex"},
			}}, //按照uid 进行分组
			{"count", bson.D{{"$sum", 1}}},                //聚合计算
			{"chanel_id", bson.D{{"$max", "$chanel_id"}}}, //model_id
			{"sex", bson.D{{"$max", "$sex"}}},             //model_id
		},
	}}
	opts := options.Aggregate().SetMaxTime(15 * time.Second)
	showInfoCursor, err := collectionBalloons.Aggregate(context.TODO(), mongo.Pipeline{match, group}, opts)
	if nil != err {
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return &resp, errors2.ErrLoadFailure
	}
	//打印文档内容
	var res []tmpBalloons
	if err = showInfoCursor.All(context.TODO(), &res); err != nil {
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return &resp, errors2.ErrLoadFailure
	}
	//遍历结束后关闭游标
	showInfoCursor.Close(context.TODO())

	//fmt.Println(logInfo)
	////查询频道数量
	//type DanceChannelRoleCommon struct {
	//	ChanelId  int64
	//	PeopleNum int64
	//	Sex       int64
	//}
	//var res []DanceChannelRoleCommon
	//tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceChannelRole{}).Where("channel_pid = ?", request.MajorId).
	//	Select("chanel_id,sum(*) as people_num,sex").Group("chanel_id,sex").Find(&res)
	//if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
	//	resp.ErrCode = pkg.ErrorLoginDataException
	//	return &resp, errors2.ErrLoadFailure
	//}
	//性别数量
	boyNumber := make(map[int64]int64, 0)
	girlNumber := make(map[int64]int64, 0)
	for _, i2 := range res {
		if i2.Sex == 1 {
			boyNumber[i2.ChanelId] = i2.Count
		} else {
			girlNumber[i2.ChanelId] = i2.Count
		}
	}
	tmpMap := make(map[uint32]*pb.ChannelVariedInfo)
	//聚合数据
	for _, i2 := range res {
		tmpMap[uint32(i2.ChanelId)] = &pb.ChannelVariedInfo{
			Id:    uint32(i2.ChanelId),
			Man:   uint32(boyNumber[i2.ChanelId]),
			Woman: uint32(girlNumber[i2.ChanelId]),
		}
	}
	var channelList []dancetiktokmodelmysql.DanceChannel
	tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceChannel{}).Where("cat_pid = ?", request.MajorId).Find(&channelList)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询角色列表异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return &resp, errors2.ErrLoadFailure
	}
	for _, channel := range channelList {
		if value, ok := tmpMap[uint32(channel.Id)]; ok {
			value.Max = uint32(channel.VipNumber + channel.CommonNumber)
			value.Url = channel.Url
			resp.List = append(resp.List, value)
		} else {
			resp.List = append(resp.List, &pb.ChannelVariedInfo{
				Id:    uint32(channel.Id),
				Man:   0,
				Woman: 0,
				Max:   uint32(channel.VipNumber + channel.CommonNumber),
				Url:   channel.Url,
			})
		}
	}
	return &resp, nil
}

func (s *Service) ChannelPlayerList(ctx context.Context, request *pb.ChannelPlayerListRequest) (*pb.ChannelPlayerListResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "ChannelPlayerList",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	resp := pb.ChannelPlayerListResponse{
		ErrCode: 0,
		List:    make([]*pb.ChannelPlayerInfo, 0),
	}
	fmt.Println(logInfo)
	//查询频道数量
	//var res []dancetiktokmodelmysql.DanceChannelRole
	////todo 这里需要处理
	//tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceChannelRole{}).Where("channel_level = ?", 3).Where("chanel_id = ?", "").
	//	Select("chanel_id,sum(*) as people_num,sex").Find(&res)
	//if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
	//	resp.ErrCode = pkg.ErrorLoginDataException
	//	return &resp, errors2.ErrLoadFailure
	//}
	//性别数量
	//boyNumber := make(map[int64]int64, 0)
	//girlNumber := make(map[int64]int64, 0)
	//for _, i2 := range res {
	//	if i2.Sex == 1 {
	//		boyNumber[i2.ChanelId] = i2.PeopleNum
	//	} else {
	//		girlNumber[i2.ChanelId] = i2.PeopleNum
	//	}
	//}
	//聚合数据
	//for _, i2 := range res {
	//	resp.List = append(resp.List, &pb.ChannelVariedInfo{
	//		Id:    uint32(i2.ChanelId),
	//		Man:   uint32(boyNumber[i2.ChanelId]),
	//		Woman: uint32(girlNumber[i2.ChanelId]),
	//		Max:   300,
	//	})
	//}
	return &resp, nil
}

func (s *Service) GetThreeChannelUrl(ctx context.Context, request *pb.GetThreeChannelUrlRequest) (*pb.GetThreeChannelUrlResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "GetThreeChannelUrl",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	resp := &pb.GetThreeChannelUrlResponse{
		ErrCode: 0,
		Url:     "",
		Status:  0,
	}
	if request.Id == 0 {
		s.logger.Error(fmt.Sprintf("参数异常 logInfo:%+v err:%+v", logInfo, nil))
		resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
		return resp, errors2.ErrLoadFailure
	}
	var channel dancetiktokmodelmysql.DanceChannel
	tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceChannel{}).Where("id = ?", request.Id).First(&channel)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
		return resp, errors2.ErrLoadFailure
	}
	if gorm.ErrRecordNotFound == tx.Error {
		s.logger.Error(fmt.Sprintf("数据不存在 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
		return resp, errors2.ErrLoadFailure
	}
	resp.Url = channel.Url
	resp.Status = uint32(channel.Status)
	return resp, nil
}

func (s *Service) SceneGetLastJoin(ctx context.Context, request *pb.SceneGetLastJoinRequest) (*pb.SceneGetLastJoinResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "SceneGetLastJoin",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	resp := &pb.SceneGetLastJoinResponse{
		ErrCode: 0,
		List:    make([]*pb.Scenemate, 0),
	}
	if request.Id == 0 {
		s.logger.Error(fmt.Sprintf("参数异常 logInfo:%+v err:%+v", logInfo, nil))
		resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
		return resp, errors2.ErrLoadFailure
	}
	//var channel dancetiktokmodelmysql.DanceChannel
	//tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceChannel{}).Where("id = ?", request.Id).First(&channel)
	//if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
	//	s.logger.Error(fmt.Sprintf("查询异常 logInfo:%+v err:%+v", logInfo, tx.Error))
	//	resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
	//	return resp, errors2.ErrLoadFailure
	//}
	//if gorm.ErrRecordNotFound == tx.Error {
	//	s.logger.Error(fmt.Sprintf("数据不存在 logInfo:%+v err:%+v", logInfo, tx.Error))
	//	resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
	//	return resp, errors2.ErrLoadFailure
	//}
	//resp.Url = channel.Url
	//resp.Status = uint32(channel.Status)
	return resp, nil
}

func (s *Service) SceneJoin(ctx context.Context, request *pb.SceneJoinRequest) (*pb.SceneJoinResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "SceneJoin",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	resp := &pb.SceneJoinResponse{
		ErrCode: 0,
		List:    make([]*pb.Scenemate, 0),
	}
	if request.Id == 0 {
		s.logger.Error(fmt.Sprintf("参数异常 logInfo:%+v err:%+v", logInfo, nil))
		resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
		return resp, errors2.ErrLoadFailure
	}

	if request.Id != 2 {

	}
	//
	if value, ok := tools.GlobalDataMapScene[2]; !ok {
		s.logger.Error(fmt.Sprintf("场景不存在 logInfo:%+v err:%+v", logInfo, nil))
		resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
		return resp, errors2.ErrLoadFailure
	} else {
		resp.Id = 2
		scenemates := make([]*pb.Scenemate, 0)

		tmpJewelry := pb.SJewelryInfo{}
		tmpJewelry.Badge = make([]uint32, 0)
		//
		var accountRole dancetiktokmodelmysql.DanceUserAccountRole
		tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceUserAccountRole{}).Where("id = ?", request.RoleId).First(&accountRole)
		if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
			s.logger.Error(fmt.Sprintf("查询角色异常 logInfo:%+v err:%+v", logInfo, tx.Error))
			resp.ErrCode = dancetiktok.ErrorLoginDataException
			return resp, errors2.ErrLoadFailure
		}
		if accountRole.Id == 0 || accountRole.AccountId == 0 {
			s.logger.Error(fmt.Sprintf("取出的数据异常 logInfo:%+v err:%+v", logInfo, tx.Error))
			resp.ErrCode = dancetiktok.ErrorLoginDataException
			return resp, errors2.ErrNotFound
		}
		tmpFashion := pb.SFashionInfo{
			Sex:   int32(accountRole.Sex),
			Skin:  int32(accountRole.Skin),
			Hair:  0,
			Face:  int32(accountRole.Face),
			Upper: int32(accountRole.Coat),
			Lower: int32(accountRole.Bottom),
			Shoes: int32(accountRole.Shoe),
			Suit1: 0,
			Suit2: 0,
		}
		split := strings.Split(value.Coordinate, "|")
		x, _ := strconv.ParseInt(split[0], 10, 64)
		y, _ := strconv.ParseInt(split[1], 10, 64)
		z, _ := strconv.ParseInt(split[2], 10, 64)
		tmp := pb.Scenemate{
			Id:        uint32(request.RoleId),
			Name:      accountRole.Name,
			Sex:       uint32(accountRole.Sex),
			Lv:        0,
			Vip:       uint32(accountRole.IsVip),
			Fashion:   &tmpFashion,
			Jewelry:   &tmpJewelry,
			GuildName: "",
			Status:    0,
			Posx:      int32(x),
			Posy:      int32(y),
			Posz:      int32(z),
			Dir:       0,
			Time:      uint32(accountRole.CreatedAt.Unix()),
		}
		scenemates = append(scenemates, &tmp)
		resp.List = append(resp.List, scenemates...)
	}
	return resp, nil
}

func (s *Service) DeleteFromChannel(ctx context.Context, request *pb.DeleteFromChannelRequest) (*pb.DeleteFromChannelResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "DeleteFromChannel",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	resp := &pb.DeleteFromChannelResponse{
		ErrCode: 0,
	}
	if request.Id == 0 {
		s.logger.Error(fmt.Sprintf("参数异常 logInfo:%+v err:%+v", logInfo, nil))
		resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
		return resp, errors2.ErrLoadFailure
	}
	filter := bson.M{}
	filter["role_id"] = request.Id
	if many, err := s.mongoDb.MongoDb.Database(fmt.Sprintf(dancetiktokenumsmymongo.DatabaseGame, s.set.EnvServer)).Collection(dancetiktokenumsmymongo.MongoDanceChannelRole).DeleteMany(context.TODO(), filter); err != nil && err != mongo.ErrNoDocuments {
		s.logger.Error(fmt.Sprintf("删除频道记录失败 logInfo:%+v err:%+v", logInfo, err))
		//resp.ErrCode = dancetiktok.TheInputTextContainsIllegalCharacters
		//return resp, errors2.ErrLoadFailure
	} else {
		s.logger.Info(fmt.Sprintf("删除用户数据数量- %+v data:%+v", many.DeletedCount, many))
	}
	return resp, nil
}

func (s *Service) ChannelFixInfo(ctx context.Context, request *pb.ChannelFixInfoRequest) (*pb.ChannelFixInfoResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "DeleteFromChannel",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	resp := &pb.ChannelFixInfoResponse{
		ErrCode: 0,
	}
	resp.MinorList = make([]*pb.ChannelFixInfo, 0)
	resp.MajorList = make([]*pb.ChannelFixInfo, 0)
	//查询角色
	var channelList []dancetiktokmodelmysql.DanceChannel
	tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceChannel{}).Find(&channelList)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询角色列表异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.NetworkAnomalyPleaseTryAgainLater
		return resp, errors2.ErrLoadFailure
	}
	for _, channel := range channelList {
		if channel.Level == dancetiktokenumsmymongo.DanceChannelRoleEnumsLevelTwo {
			resp.MajorList = append(resp.MajorList, &pb.ChannelFixInfo{
				Id:   uint32(channel.Id),
				Name: channel.Name,
			})
		} else if channel.Level == dancetiktokenumsmymongo.DanceChannelRoleEnumsLevelThree {
			resp.MinorList = append(resp.MinorList, &pb.ChannelFixInfo{
				Id:   uint32(channel.Id),
				Name: channel.Name,
			})
		}
	}
	return resp, nil
}
